#!/usr/bin/env python2

# Author: Jamie Davis (davisjam@vt.edu)
# Description: Script for transforming libuv event schedules: "rescheduling" to flip the order of events in a legal way
# Python version: 2.7.6

import argparse
import copy
import logging
import re
import sys

import Callback as CB
import Schedule

logger = logging.getLogger('root')
LOG_FORMAT = "[%(filename)s:%(lineno)s - %(funcName)20s() ] %(message)s"
logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)
sys.setrecursionlimit(1000000) # Graph algorithms, deep trees

def main():
	parser = argparse.ArgumentParser(description="Produce schedules to explore races. One schedule for each race group is produced.")
	parser.add_argument("--schedFile", help="file containing libuv event schedule", required=True, type=str)	
	parser.add_argument("--raceFile", help="Set of racey nodes (format: 'Group i' followed by one exec ID per line)", required=True, type=str)
	parser.add_argument("--outputPrefix", help="Save schedules to outputPrefix_i, one for each race in raceFile", type=str, default="raceySchedule")

	args = parser.parse_args()

	logging.info("schedFile {} raceFile {} outputPrefix {}".format(args.schedFile, args.raceFile, args.outputPrefix))

	logging.info("Loading the callback cbTree from schedFile {}".format(args.schedFile))

	try:
		logging.info("Loading the races from raceFile {}".format(args.raceFile))
		raceyNodes = CB.CallbackNodeGroups(args.raceFile).getNodeGroups()
	except IOError:
		logging.error("Error, reading raceFile {} failed".format(args.raceFile))
		raise

	for (ix, race) in enumerate(raceyNodes):
		outFile = "{}_{}".format(args.outputPrefix, ix)
		schedule = Schedule.Schedule(args.schedFile)
		try:
			logging.info("Generating schedule for race <{}>".format(race))
			idMap = schedule.reschedule(race)
			logging.info("The schedule from race <{}> is going into outFile {}".format(race, outFile))
			mapStrings = ["{} -> {}".format(id, idMap[id]) for id in idMap]
			logging.info("racy schedule {}: schedFile {} id mappings {}".format(ix, outFile, mapStrings))
			schedule.emit(outFile)
		except Schedule.ScheduleException as se:
			logging.info("Sorry, could not achieve race <{}>: {}".format(race, se))
		except IOError:
			logging.error("Error, could not write schedule to file <{}>".format(outFile))
			raise

###################################

main()
